package com.example.ssmxuankeback.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.ssmxuankeback.common.RestBean;
import com.example.ssmxuankeback.dto.UserDTO;
import com.example.ssmxuankeback.dto.UserPageQueryDTO;
import com.example.ssmxuankeback.entity.User;
import com.example.ssmxuankeback.exception.BusinessException;
import com.example.ssmxuankeback.interfaces.IUserMapper;
import com.example.ssmxuankeback.mapper.UserMapper;
import com.example.ssmxuankeback.service.UserService;
import com.example.ssmxuankeback.vo.PageVO;
import com.example.ssmxuankeback.vo.UserVO;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {

    private final UserMapper userMapper;
    private final IUserMapper userConverter = IUserMapper.INSTANCT;

    @CacheEvict(value = "users", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public RestBean<UserVO> register(UserDTO dto) {
        try {
            checkUserUniqueness(dto);
            User user = userConverter.dtoToEntity(dto);
            user.setPassword(dto.getPassword());
            userMapper.insert(user);
            return RestBean.success(userConverter.entityToVO(user));
        } catch (DuplicateKeyException e) {
            throw new BusinessException("用户标识已存在");
        }
    }

    @Transactional(readOnly = true)
    @Override
    public RestBean<UserVO> login(UserDTO dto) {
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getId, dto.getId())
                .eq(User::getPassword, dto.getPassword()));
        if (user == null) {
            throw new BusinessException("账号或密码错误");
        }
        return RestBean.success(userConverter.entityToVO(user));
    }

    @CacheEvict(value = "users", key = "#dto.id")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public RestBean<UserVO> update(UserDTO dto) {
        User user = userConverter.dtoToEntity(dto);
        int result = userMapper.updateById(user);
        if (result == 0) {
            throw new BusinessException("用户不存在");
        }
        return RestBean.success(userConverter.entityToVO(user));
    }

    @CacheEvict(value = "users", key = "#userId")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public RestBean<UserVO> delete(Long userId) {
        int result = userMapper.deleteById(userId);
        if (result == 0) {
            throw new BusinessException("用户不存在");
        }
        return RestBean.success();
    }

    @Cacheable(value = "users", key = "#userId")
    @Transactional(readOnly = true)
    @Override
    public RestBean<UserVO> getUserById(Long userId) {
        User user = userMapper.selectById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        }
        return RestBean.success(userConverter.entityToVO(user));
    }

    @Transactional(readOnly = true)
    @Override
    public RestBean<PageVO<UserVO>> listByPage(UserPageQueryDTO queryDTO) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        // 条件过滤
        if (StringUtils.hasText(queryDTO.getName())) {
            wrapper.like(User::getName, queryDTO.getName());
        }
        if (queryDTO.getClassId() != null) {
            wrapper.eq(User::getClassId, queryDTO.getClassId());
        }
        if (queryDTO.getUserType() != null) {
            wrapper.eq(User::getUserType, queryDTO.getUserType());
        }
        // 排序
        if (StringUtils.hasText(queryDTO.getSortBy())) {
            String order = "asc".equalsIgnoreCase(queryDTO.getSortOrder()) ? "ASC" : "DESC";
            wrapper.orderBy(true, "asc".equalsIgnoreCase(order), getSortField(queryDTO.getSortBy()));
        }
        // 分页查询
        IPage<User> page = new Page<>(queryDTO.getPageNum(), queryDTO.getPageSize());
        IPage<User> pageResult = userMapper.selectPage(page, wrapper);
        // 转换为VO
        List<UserVO> voList = pageResult.getRecords().stream()
                .map(userConverter::entityToVO)
                .collect(Collectors.toList());
        PageVO<UserVO> pageVO = PageVO.<UserVO>builder()
                .total(pageResult.getTotal())
                .pages(pageResult.getPages())
                .records(voList)
                .build();
        return RestBean.success(pageVO);
    }

    @Override
    public RestBean<List<UserVO>> getUsersByClassId(Long classId) {
        List<User> users = userMapper.selectList(new LambdaQueryWrapper<User>()
                .eq(User::getClassId, classId));
        return RestBean.success(users.stream()
                .map(userConverter::entityToVO)
                .collect(Collectors.toList()));
    }

    @Override
    public boolean hasStudentsInClass(Long classId) {
        return userMapper.selectCount(new LambdaQueryWrapper<User>()
                .eq(User::getClassId, classId)
                .eq(User::getUserType, 0)) > 0;
    }

    // -------------------- 私有方法 --------------------
    private void checkUserUniqueness(UserDTO dto) {
        boolean exists = userMapper.exists(new LambdaQueryWrapper<User>()
                .eq(User::getName, dto.getName())
                .or()
                .eq(User::getPhone, dto.getPhone()));
        if (exists) {
            throw new BusinessException("用户名或手机号已被注册");
        }
    }

    private SFunction<User, ?> getSortField(String sortBy) {
        if (sortBy.equalsIgnoreCase("createtime")) {
            return User::getCreateTime;
        }
        return User::getId;
    }
}